#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import sys

from common import cleaner
from common.common import exter_attack
from common.const import ExecuteResultEnum, SysData
from common.job_const import JobNameConst
from common.parse_parafile import ParamFileUtil
from common.util.check_utils import is_valid_id
from gaussdbt.single import LOGGER
from gaussdbt.single.backup.gst_single_backup import GstSingleBackup
from gaussdbt.single.comm.gst_single_const import GstSingleConst
from gaussdbt.single.comm.utils.gst_single_comm_utils import GstSingleCommonUtil


@exter_attack
def distribute_task(task_name: str, pid: str, job_id: str, param_dict: dict, sub_job_id=None):
    """分发任务"""
    gst_backup_inst = GstSingleBackup(task_name, pid, job_id, sub_job_id, param_dict)
    job_name_func_mappings = build_job_name_func_mappings(gst_backup_inst)

    # 异常处理，下发不存在的请求
    job_func_dict = job_name_func_mappings.get(task_name)
    if not job_func_dict:
        LOGGER.error(f"Unsupported job action: %s, pid: %s, job_id: %s, sub_job_id: %s.",
                     task_name, pid, job_id, sub_job_id)
        err_msg = f"Unsupported job action: {task_name}."
        GstSingleCommonUtil.output_action_result(pid, ExecuteResultEnum.INTERNAL_ERROR.value, message=err_msg)
        return

    # 调用任务对应的执行函数
    action_ret = job_func_dict["exec_job_func"]()
    # 写执行步骤的执行结果
    if job_func_dict.get("output_result_func"):
        job_func_dict["output_result_func"](action_ret)


def build_job_name_func_mappings(gst_backup_inst: GstSingleBackup):
    job_name_func_mappings = {
        JobNameConst.ALLOW_BACKUP_IN_LOCAL: {
            "exec_job_func": gst_backup_inst.allow_backup_in_local_node,
            "output_result_func": gst_backup_inst.output_action_result,
        },
        JobNameConst.CHECK_BACKUP_JOB_TYPE: {
            "exec_job_func": gst_backup_inst.check_backup_job_type,
            "output_result_func": gst_backup_inst.output_action_result
        },
        JobNameConst.QUERY_PERMISSION: {
            "exec_job_func": gst_backup_inst.query_job_permission
        },
        JobNameConst.BACKUP_PRE: {
            "exec_job_func": gst_backup_inst.exec_backup_pre_job,
            "output_result_func": gst_backup_inst.output_action_result
        },
        JobNameConst.BACKUP: {
            "exec_job_func": gst_backup_inst.exec_backup,
            "output_result_func": gst_backup_inst.output_action_result
        },
        JobNameConst.BACKUP_POST: {
            "exec_job_func": gst_backup_inst.exec_backup_post_job
        },
        JobNameConst.ABORT_JOB: {
            "exec_job_func": gst_backup_inst.abort_job
        }
    }
    return job_name_func_mappings


@exter_attack
def main():
    args = sys.argv[1:]
    for line in sys.stdin:
        SysData.SYS_STDIN = line
        break
    # 参数个数为3或者4
    if len(args) not in (2, 3, 4):
        LOGGER.error("Param number error! Arguments: %s", args)
        return ExecuteResultEnum.INTERNAL_ERROR

    task_name, pid = args[0], args[1]
    job_id = args[2] if len(args) >= 3 else ""
    sub_job_id = args[3] if len(args) == 4 else ""
    LOGGER.info("[%s] Start executing task, task name: %s, pid: %s, job_id: %s, sub_job_id: %s.",
                '#' * 8, task_name, pid, job_id, sub_job_id)
    # 校验pid, job_id, sub_job_id
    if not is_valid_id(pid):
        LOGGER.warn(f'pid is invalid!')
        sys.exit(1)
    if not is_valid_id(job_id):
        LOGGER.warn(f'job_id is invalid!')
        sys.exit(1)
    if not is_valid_id(sub_job_id):
        LOGGER.warn(f'sub_job_id is invalid!')
        sys.exit(1)
    try:
        param_dict = ParamFileUtil.parse_param_file_and_valid_by_schema(pid, GstSingleConst.JSON_SCHEMA_PATH)
    except Exception:
        LOGGER.exception("Parse param file failed, task name: %s, pid: %s.", task_name, pid)
        err_msg = "Parse parameter file failed."
        GstSingleCommonUtil.output_action_result(pid, ExecuteResultEnum.INTERNAL_ERROR.value, message=err_msg)
        return ExecuteResultEnum.INTERNAL_ERROR

    try:
        distribute_task(task_name, pid, job_id, param_dict, sub_job_id=sub_job_id)
    except Exception:
        LOGGER.exception("Distribute backup task failed, task name: %s, pid: %s, job_id: %s, sub_job_id: %s.",
                         task_name, pid, job_id, sub_job_id)
        return ExecuteResultEnum.INTERNAL_ERROR
    LOGGER.info("[%s] Execute task success, task name: %s, pid: %s, job_id: %s, sub_job_id: %s.",
                '#' * 8, task_name, pid, job_id, sub_job_id)
    return ExecuteResultEnum.SUCCESS


if __name__ == '__main__':
    try:
        sys.exit(main())
    finally:
        cleaner.clear(SysData.SYS_STDIN)
